#ifndef AFCORE_COMMON_LOG_ASYNC_ASYNC_
#define AFCORE_COMMON_LOG_ASYNC_ASYNC_

#pragma once

#include "async_logger.h"
#include "async_thread_pool.h"
#include "log_hub.h"

namespace afcore {

/// @brief  日志
namespace log {

static const size_t kDefaultAsyncQueueSize = 8192; ///< 默认异步队列大小

/// @brief  异步工厂
/// @tparam OverflowPolicy  异步策略 默认阻塞
template<EAsyncOverflowPolicy OverflowPolicy = EAsyncOverflowPolicy::kAsyncOverflowPolicy_Block>
struct SAsyncFactory {
  /// @brief  创建异步记录器
  /// @tparam Appender        异步记录器类型
  /// @tparam ...Args         记录器所需参数
  /// @param  logger_name     记录器名称
  /// @param  ...args         记录器所需参数
  /// @return 异步记录器
  template<typename Appender, typename... Args>
  static std::shared_ptr<CAsyncLogger> Create(std::string logger_name, Args&&... args) {
    auto& log_hub = CLogHub::Instance();
    auto& mutex = log_hub.GetTpMutex();
    std::lock_guard<std::recursive_mutex> lock(mutex);
    auto tp = log_hub.GetThreadPool();
    if (nullptr == tp) {
      tp = std::make_shared<CAsyncThreadPool>(kDefaultAsyncQueueSize, 1);
      log_hub.SetThreadPool(tp);
    }

    auto appender = std::make_shared<Appender>(std::forward<Args>(args)...);
    auto new_logger = std::make_shared<CAsyncLogger>(std::move(logger_name), std::move(appender), std::move(tp), OverflowPolicy);
    log_hub.InitializeLogger(new_logger);
    return new_logger;
  }
};

using RAsyncFactory = SAsyncFactory<EAsyncOverflowPolicy::kAsyncOverflowPolicy_Block>;
using RAsyncFactoryNonBlock = SAsyncFactory<EAsyncOverflowPolicy::kAsyncOverflowPolicy_OverrunOldest>;

} // !namespace log

using namespace log;

/// @brief  创建异步记录器 阻塞
/// @tparam Appender        异步记录器类型
/// @tparam ...Args         记录器所需参数
/// @param  logger_name     记录器名称
/// @param  ...args         记录器所需参数
/// @return 异步记录器
template<typename Appender, typename... Args>
std::shared_ptr<CAsyncLogger> CreateAsync(std::string logger_name, Args&&... args) {
  return RAsyncFactory::Create<Appender>(std::move(logger_name), std::forward<Args>(args)...);
}

/// @brief  创建异步记录器 非阻塞
/// @tparam Appender        异步记录器类型
/// @tparam ...Args         记录器所需参数
/// @param  logger_name     记录器名称
/// @param  ...args         记录器所需参数
/// @return 异步记录器
template<typename Appender, typename... Args>
std::shared_ptr<CAsyncLogger> CreateAsyncNonBlock(std::string logger_name, Args&&... args) {
  return RAsyncFactoryNonBlock::Create<Appender>(std::move(logger_name), std::forward<Args>(args)...);
}

/// @brief  初始化线程池
/// @param  q_max_items     消息最大容量
/// @param  threads_n       线程池容量
/// @param  on_thread_start 线程启动处理操作
void InitThreadPool(size_t q_max_items, size_t threads_n, std::function<void()> on_thread_start) {
  auto tp = std::make_shared<CAsyncThreadPool>(q_max_items, threads_n, on_thread_start);
  CLogHub::Instance().SetThreadPool(std::move(tp));
}

/// @brief  初始化线程池
/// @param  q_max_items     消息最大容量
/// @param  threads_n       线程池容量
void InitThreadPool(size_t q_max_items, size_t threads_n) {
  InitThreadPool(q_max_items, threads_n, []{});
}

/// @brief  获取线程池
/// @return 全局线程池
std::shared_ptr<CAsyncThreadPool> GetThreadPool() {
  return CLogHub::Instance().GetThreadPool();
}

} // !namespace afcore

#endif //! AFCORE_COMMON_LOG_ASYNC_ASYNC_